//	--------------------------------------------------------------------
//	Copyright(C) 2006,2007 Zhao Yukun. All rights reserved.
//	This file is a part of the Xeres system.
//	Xeres 2007
//	Contact : xeres.engine@gmail.com
//	$(reservedInfo)
//	$(reservedDeclaration)
//	--------------------------------------------------------------------
///	@file	<CScreen9.cpp>
///	@path	~/src/graphics/dx9/
///	@date	2007/10/19
///	@desc	.

#include "config/config.h"

#include "graphics/dx9/CScreen9.h"

namespace xeres {

	IMPL_IOBJECT_CLASS( CScreen9 );

	// ctor
	CScreen9::CScreen9( void )
		: m_hWnd( NULL )
		, m_swapChain( NULL )
	{
		memset( &m_presentParameters , 0 , sizeof(D3DPRESENT_PARAMETERS) );
		memset( &m_backBufferSurfaceDesc , 0 , sizeof(D3DSURFACE_DESC) );
	}

	// dtor
	CScreen9::~CScreen9( void )
	{
	}

	// update back buffer desc
	void CScreen9::UpdateBackBufferDesc( void )
	{
		HRESULT hr;
		if( m_swapChain )
		{
			IDirect3DSurface9 * pBackBuffer;
			hr = m_swapChain->GetBackBuffer( 0 , D3DBACKBUFFER_TYPE_MONO , &pBackBuffer );
			memset( &m_backBufferSurfaceDesc , 0 , sizeof(D3DSURFACE_DESC) );
			if( SUCCEEDED(hr) )
			{
				pBackBuffer->GetDesc( &m_backBufferSurfaceDesc );
				pBackBuffer->Release();
			}
		}
	}

	// initialize
	bool CScreen9::Initialize( void * window , RefWeak<IDevice> device )
	{
		if( ::IsWindow( (HWND)window ) == FALSE )
		{
			TRACE_ERROR( _S("CScreen9::initialize: Input handle is not a valid window.") );
			return false;
		}
		m_hWnd = (HWND)window;

		if( !device->IsA<CDevice9>() )
		{
			TRACE_ERROR( _S("CScreen9:initialize: Input device is not a CDevice9 class.") );
			return false;
		}
		m_device = device;

		RECT rect;
		::GetClientRect( m_hWnd , &rect );

		// initialize back buffer parameters
		m_presentParameters.BackBufferFormat = D3DFMT_X8R8G8B8;
		m_presentParameters.BackBufferWidth = rect.right - rect.left;
		m_presentParameters.BackBufferHeight = rect.bottom - rect.top;
		m_presentParameters.BackBufferCount = 2;
		m_presentParameters.MultiSampleType = D3DMULTISAMPLE_NONE;
		m_presentParameters.MultiSampleQuality = 0;
		m_presentParameters.SwapEffect = D3DSWAPEFFECT_DISCARD;
		m_presentParameters.Windowed = TRUE;
		m_presentParameters.hDeviceWindow = m_hWnd;
		m_presentParameters.EnableAutoDepthStencil = TRUE;
		m_presentParameters.AutoDepthStencilFormat = D3DFMT_D24S8;
		m_presentParameters.Flags =
			D3DPRESENTFLAG_DEVICECLIP |
			D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL;
		m_presentParameters.FullScreen_RefreshRateInHz = 0;
		m_presentParameters.PresentationInterval  = 0;

		HRESULT hr = (*m_device)->CreateAdditionalSwapChain( &m_presentParameters , &m_swapChain );
		if( FAILED(hr) )
		{
			// trace
			return false;
		}

		UpdateBackBufferDesc();
		return true;
	}

	// finalize
	void CScreen9::Finalize( void )
	{
		m_device = NULL;
		m_hWnd = NULL;
		if( m_swapChain )
		{
			UINT rest = m_swapChain->Release();
			m_swapChain = NULL;
			if( rest != 0 )
			{
				TRACE_ERROR( _S("CScreen9::finalize: Invalid swap chain reference count.") );
				FATAL_ABORT( _S("Invalid swap chain referece count.") );
			}
		}
	}

	// get window
	void * CScreen9::GetWindow( void )
	{
		return m_hWnd;
	}

	// check for size change
	void CScreen9::CheckForSizeChange( void )
	{
		UINT rest = m_swapChain->Release();
		m_swapChain = NULL;
		if( rest != 0 )
		{
			TRACE_ERROR( _S("CScreen9::finalize: Invalid swap chain reference count.") );
			FATAL_ABORT( _S("Invalid swap chain referece count.") );
		}

		// change size
		RECT rect;
		::GetClientRect( m_hWnd , &rect );

		m_presentParameters.BackBufferWidth = rect.right - rect.left;
		m_presentParameters.BackBufferHeight = rect.bottom - rect.top;
		HRESULT hr = (*m_device)->CreateAdditionalSwapChain( &m_presentParameters , &m_swapChain );
		if( FAILED(hr) )
		{
			// trace
			FATAL_ABORT( _S("Failed to create additional swap chain.") );
		}
		UpdateBackBufferDesc();
	}

	void CScreen9::GetSize( int& width , int& height )
	{
		width = m_presentParameters.BackBufferWidth;
		height = m_presentParameters.BackBufferHeight;
	}

	// on size
	void CScreen9::OnSize( bool minimized )
	{
		if( m_swapChain && !m_ignoreSizeChange )
		{
			if( !minimized )
			{
				CheckForSizeChange();
			}
			m_minimized = minimized;
		}
	}

	// on moved
	void CScreen9::OnMoved( void )
	{

	}

	// begin render
	bool CScreen9::BeginRender( void )
	{
		if( m_noUpdate || m_minimized )
			return false;

//		m_swapChain->GetBackBuffer(0,D3DBACKBUFFER_TYPE_MONO,&pBack );
//		(*m_device)->GetDepthStencilSurface(&pStencil);
//		(*m_device)->SetRenderTarget(pBack,pStencil);
//		pBack->Release();
//		pStencil->Release();

		return true;
	}

	// end render
	void CScreen9::EndRender( void )
	{
		assert( !m_noUpdate && !m_minimized );
		assert( m_swapChain );

		HRESULT hr = m_swapChain->Present( NULL , NULL , NULL , NULL , 0 );
		if( FAILED(hr) )
		{
			//
		}
	}

} // namespace xeres
